
function WebMail()
{
	this.serverUrl = 'server.php';
	this.mailUrl = 'mail.php';
	this.d = '/';
	
	this.data = {
		Application: {},
		Settings: {},
		Folders: {}
	};

	this.autoCompleteData = {};
	
	this.screens = {};
	this.screen = null;
	
	this.currentAction = null;

	this.domains = {
		'dom.local': ['localhost', 143],
		'afterlogic.com': ['mail.afterlogic.com', 143],
		'mailstone.net': ['mail.mailstone.net', 143],
		'gmail.com': ['imap.gmail.com', 993]
	};

	$.fn.pureJSTemplate.setDelimiters('<%', '%>');

	var auth = $.cookie('xwm_auth');
	this.screen = (auth && 0 < auth.length) ? 'mail' : 'login';

	this.ajaxRequest('GetApplicationSettings', {}, false);
	$(document).attr('title', this.data.Application.Title);

	if ('login' === this.screen)
	{
		this.screens['login'] = new WebMailLoginScreen(this);
	}
	else if ('mail' === this.screen)
	{
		this.screens['mail'] = new WebMailMailScreen(this);
	}

	if ('undefined' !== typeof(this.screens[this.screen]))
	{
		this.screens[this.screen].initScreen();
		$('#loading').addClass('hide');
	}
	else
	{
		// TODO
	}
}

WebMail.prototype = 
{
	/**
	 * @param {string} sAction
	 * @param {object} oParams = {}
	 * @param {bool} bIsAsync = true
	 * @return {void}
	 */
	ajaxRequest: function (sAction, oParams, bIsAsync)
	{
		oParams = 'undefined' !== typeof(oParams) ? oParams : {};
		bIsAsync = 'undefined' !== typeof(bIsAsync) ? bIsAsync : true;

		oParams.action = sAction;
		oParams.timeoffset = new Date().getTimezoneOffset();

		var obj = this;
		$.ajax({
			type: 'POST', url: this.serverUrl, async: bIsAsync, dataType: 'json', data: oParams,
			success: function (jData){
				obj.ajaxParseResponse(jData);
			},
			error: function (sData, sTextStatus) {
				obj.ajaxAppError(sData, sTextStatus);
			}
		});
	},

	/**
	 * @param {string} sData
	 * @param {string} sTextStatus
	 * @return {void}
	 */
	ajaxAppError: function (sData, sTextStatus)
	{
		this.currentAction = null;
		alert('Error: ' + sData + ' [' + sTextStatus + ']');
	},

	/**
	 * @param {mixed} mJson
	 * @return {void}
	 */
	ajaxParseResponse: function (mJson)
	{
		if (mJson)
		{
			if (0 < mJson.length) // multi response
			{
				for (var i in mJson)
				{
					if ('undefined' !== typeof(mJson[i].Action))
					{
						this.buildResponseItem(mJson[i]);
					}
				}
			}
			else if ('undefined' !== typeof(mJson.Action)) // single response
			{
				this.buildResponseItem(mJson);
			}
		}
	},

	/**
	 * @return {array}
	 */
	getAutoCompleteArray: function ()
	{
		var aAuto = [];
		for (var sItem in this.autoCompleteData)
		{
			aAuto.push(sItem);
		}
		return aAuto;
	},

	/**
	 * @param {object} oItem
	 * @return {void}
	 */
	buildResponseItem: function (oItem)
	{
		var sAction = oItem.Action || null;
		var sError = oItem.Error || null;
		var bCheckLastAction = false;

		if (null !== sAction && oItem.Response)
		{
			if ('undefined' !== typeof(oItem.Auth) && 14 < oItem.Auth.length)
			{
				$.cookie('xwm_auth', oItem.Auth, {expires: this.data.Application.ExpiresSession});
			}

			var sResponseSceen = '';
			switch (sAction) {
				case 'GetApplicationSettings':
				case 'GetAccountSettings':
				case 'SetListFlags':
				case 'DeleteMessages':
					break;
				case 'Login':
					sResponseSceen = 'login';
					break;
				case 'GetFolders':
				case 'GetMessages':
				case 'GetMessagesHeaders':
				//case 'GetList':
				//case 'GetListHash':
					bCheckLastAction = true;
					sResponseSceen = 'mail';
					break;
			}

			if (0 < sResponseSceen.length && 'undefined' !== typeof(this.screens[sResponseSceen]))
			{
				this.screens[sResponseSceen].buildResponseItem(sAction, oItem);
			}
			else
			{
				this.appBuildResponseItem(sAction, oItem);
			}
		}
		else if (null === sError)
		{
			sError = 'False response';
		}

		if (null !== sError)
		{
			this.ajaxAppError(sError, 'Response Error');
		}
		else
		{
			if (bCheckLastAction)
			{
				this.checkLastAction();
			}
		}
	},

	/**
	 * @param {string} sAction
	 * @param {object} oItem
	 * @return {void}
	 */
	appBuildResponseItem: function (sAction, oItem)
	{
		switch (sAction)
		{
			case 'GetApplicationSettings':
				if ('boolean' === typeof(oItem.Response.CheckField))
				{
					this.data.Application = oItem.Response;
				}
				break;
			case 'GetAccountSettings':
				if ('boolean' === typeof(oItem.Response.CheckField))
				{
					this.data.Settings = oItem.Response;
				}
				break;
			case 'SetListFlags':
			case 'DeleteMessages':
				// null
				break;
		}
	},

	/**
	 * @return {void}
	 */
	checkLastAction: function ()
	{
		if (null !== this.currentAction)
		{
			this.prepearHash(this.currentAction);
		}
	},

	/**
	 * @param {string} sHash
	 * @param {bool} bOnlyCacheBuild
	 * @return {bool}
	 */
	prepearHash: function (sHash, bOnlyCacheBuild)
	{
		bOnlyCacheBuild = ('' === typeof(bOnlyCacheBuild)) ? false : bOnlyCacheBuild;
		if (this.appBuildHash(sHash))
		{
			if (!bOnlyCacheBuild)
			{
				this.currentAction = null;
				if (sHash !== $.History.getHash())
				{
					this.goToHash(sHash);
				}
				else
				{
					this.appSetActiveHash(sHash);
				}
			}
			else
			{
				this.appSetActiveHash(sHash);
			}
		}
		else
		{
			if (!bOnlyCacheBuild)
			{
				this.currentAction = sHash;
			}
		}

		return true;
	},

	/**
	 * @param {string} sHash
	 * @return {void}
	 */
	goToHash: function (sHash)
	{
		if ('undefined' !== typeof(window.location.hash))
		{
			window.location.hash = sHash;
		}
		else
		{
			location.hash = sHash;
		}
	},

	/**
	 * @param {string} sHash
	 * @return {bool}
	 */
	appBuildHash: function (sHash)
	{
		if ('undefined' !== typeof(this.screens[this.screen]))
		{
			return this.screens[this.screen].buildHash(sHash);
		}
		else
		{
			return false;
		}
	},

	/**
	 * @param {string} sHash
	 * @return {bool}
	 */
	appSetActiveHash: function (sHash)
	{
		if ('undefined' !== typeof(this.screens[this.screen]))
		{
			return this.screens[this.screen].setActiveHash(sHash);
		}
		else
		{
			return false;
		}
	},

	/**
	 * @param {object} oHash
	 * @return {string}
	 */
	generateHash: function (oHash)
	{
		var sFolder, sUid, sSearch, sScreen;

		sFolder = oHash.folder || null;
		sUid = oHash.uid || null;
		sSearch = oHash.search || null;
		sScreen = oHash.screen || null;

		var sOut = '';
		if (null !== sScreen && 0 < sScreen.toString().length)
		{
			sOut += this._encode(sScreen.toString());
		}
		if (null !== sFolder && 0 < sFolder.toString().length)
		{
			sOut += this.d + 'folder' + this.d + this._encode(sFolder.toString());
		}
		if (null !== sUid && 0 < sUid.toString().length)
		{
			sOut += this.d + 'uid' + this.d + this._encode(sUid.toString());
		}
		if (null !== sSearch && 0 < sSearch.toString().length)
		{
			sOut += this.d + 'search' + this.d + this._encode(sSearch.toString());
		}
		return sOut;
	},

	/**
	 * @param {string} sHash
	 * @return {object}
	 */
	parseHash: function (sHash)
	{
		sHash = ('undefined' === typeof(sHash)) ? '' : sHash;
		var oReturn = {folder: null, uid: null, search: null, screen: null};
		var aParts = sHash.split(this.d);
		var sType = null;
		var aValues = ['folder', 'uid', 'search'];
		for (var i in aParts)
		{
			if (0 < aParts[i].length)
			{
				if (null === sType)
				{
					sType = aParts[i];
					if (0 == i && ('compose' === sType || 'settings' === sType))
					{
						oReturn.screen = sType;
						sType = null;
					}
				}
				else
				{
					var iIndex = $.inArray(sType, aValues);
					if (-1 < iIndex)
					{
						oReturn[aValues[iIndex]] = aParts[i];
					}

					sType = null;
				}
			}
		}

		for (var sKey in oReturn)
		{
			if (null !== oReturn[sKey])
			{
				oReturn[sKey] = this._decode(oReturn[sKey]);
			}
		}

		return oReturn;
	},

	/**
	 * @param {string} sValue
	 * @return {string}
	 */
	_decode: function (sValue)
	{
		return decodeURIComponent(sValue.replace(/\+/g, ' '));
	},

	/**
	 * @param {string} sValue
	 * @return {string}
	 */
	_encode: function (sValue)
	{
		return encodeURIComponent(sValue).replace(/%20/g, '+');
	}
}